import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;

import codeg.Codeg;
import gui.SWTCodegGUI;

class TableCodegEditor
{
    public void run(Composite parent, final TableContent content)
    {
        Display display = parent.getDisplay();
        final Shell shell = new Shell(display);

        shell.setLayout(new GridLayout(2, false));
        final Table table = new Table(shell, SWT.BORDER | SWT.MULTI);
        GridData gd = new GridData();
        gd.horizontalAlignment = GridData.FILL;
        gd.grabExcessHorizontalSpace = true;
        gd.verticalAlignment = GridData.FILL;
        gd.grabExcessVerticalSpace = true;
        gd.horizontalSpan = 2;
        table.setLayoutData(gd);
        table.setLinesVisible(true);

        gd = new GridData();
        gd.horizontalAlignment = GridData.FILL;
        gd.grabExcessHorizontalSpace = true;

        final Button add_row = new Button(shell, SWT.PUSH);
        add_row.setLayoutData(gd);
        add_row.setText("Add row");
        add_row.addListener(SWT.MouseUp, new Listener() {
            public void handleEvent(Event e)
            {
                content.new_row();
                updateContent(table, content);
            }
        });

        final Button add_col = new Button(shell, SWT.PUSH);
        add_col.setLayoutData(gd);
        add_col.setText("Add column");
        add_col.addListener(SWT.MouseUp, new Listener() {
            public void handleEvent(Event e)
            {
                content.new_col();
                updateContent(table, content);
            }
        });

        final Button del_row = new Button(shell, SWT.PUSH);
        del_row.setLayoutData(gd);
        del_row.setText("Remove row");
        del_row.addListener(SWT.MouseUp, new Listener() {
            public void handleEvent(Event e)
            {
                content.del_row();
                updateContent(table, content);
            }
        });

        final Button del_col = new Button(shell, SWT.PUSH);
        del_col.setLayoutData(gd);
        del_col.setText("Remove column");
        del_col.addListener(SWT.MouseUp, new Listener() {
            public void handleEvent(Event e)
            {
                content.del_col();
                updateContent(table, content);
            }
        });

        final Button close = new Button(shell, SWT.PUSH);
        gd = new GridData();
        gd.horizontalAlignment = GridData.END;
        gd.horizontalSpan = 2;
        close.setLayoutData(gd);
        close.setText("Close");
        close.addListener(SWT.MouseUp, new Listener() {
            public void handleEvent(Event e)
            {
                shell.dispose();
            }
        });

        final TableEditor editor = new TableEditor(table);
        editor.horizontalAlignment = SWT.LEFT;
        editor.grabHorizontal = true;

        updateContent(table, content);
        
        // Based on: http://dev.eclipse.org/viewcvs/viewvc.cgi/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet124.java?view=co
        table.addListener(SWT.MouseDown, new Listener() {
            public void handleEvent(Event event)
            {
                Rectangle area = table.getClientArea();

                Point pt = new Point(event.x, event.y);

                int index = table.getTopIndex();
                while (index < table.getItemCount())
                {
                    boolean visible = false;
                    final TableItem item = table.getItem(index);
                    for (int i = 0; i < table.getColumnCount(); i++)
                    {
                        Rectangle rect = item.getBounds(i);
                        if (rect.contains(pt))
                        {
                            final int column = i;
                            final Text text = new Text(table, SWT.NONE);

                            Listener textListener = new Listener() {
                                public void modifyTable(TableItem i, Text t)
                                {
                                    i.setText(column, t.getText());

                                    int row = (Integer) i.getData("row");
                                    content.set_value(row, column,
                                            Integer.parseInt(t.getText()));
                                }

                                public void handleEvent(final Event e)
                                {
                                    switch (e.type)
                                    {
                                        case SWT.FocusOut:
                                            modifyTable(item, text);
                                            text.dispose();
                                            break;
                                        case SWT.Traverse:
                                            switch (e.detail)
                                            {
                                                case SWT.TRAVERSE_RETURN:
                                                    modifyTable(item, text);
                                                case SWT.TRAVERSE_ESCAPE:
                                                    text.dispose();
                                                    e.doit = false;
                                            }
                                            break;
                                    }
                                }
                            };
                            text.addListener(SWT.FocusOut, textListener);
                            text.addListener(SWT.Traverse, textListener);
                            editor.setEditor(text, item, i);
                            text.setText(item.getText(i));
                            text.selectAll();
                            text.setFocus();
                            return;
                        }
                        if (!visible && rect.intersects(area))
                            visible = true;
                    }
                    if (!visible)
                        return;
                    index++;
                }
            }
        });

        shell.pack();
        shell.open();
        while (!shell.isDisposed())
        {
            if (!display.readAndDispatch())
                display.sleep();
        }
        if (!shell.isDisposed())
            shell.dispose();
    }

    private static void updateContent(Table table, TableContent content)
    {
        table.removeAll();
        while (table.getColumnCount() > 0)
            table.getColumn(0).dispose();

        for (int i = 0; i < content.get_cols(); i++)
        {
            TableColumn column = new TableColumn(table, SWT.NONE);
            column.setWidth(50);
        }

        for (int i = 0; i < content.get_rows(); i++)
        {
            TableItem item = new TableItem(table, SWT.NONE);
            item.setData("row", i);
            for (int j = 0; j < content.get_cols(); j++)
            {
                item.setText(j, Integer.toString(content.get_value(i, j)));
            }
        }
    }
}

public class MatrixCodegGUI implements SWTCodegGUI {
    MatrixCodeg codeg;
    
    public void populate(final Composite area)
    {
        area.setLayout(new GridLayout(1, false));

        Label label = new Label(area, SWT.LEFT);
        label.setText("Current value: ");

        final Composite table = new Composite(area, SWT.NONE);
        table.setLayout(new GridLayout(codeg.content.get_cols(), false));
        table.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true, 1,
                1));

        Label l;
        FontData fd = new FontData("sans", 10, SWT.BOLD);
        Font f = new Font(area.getDisplay(), fd);
        for (int i = 0; i < codeg.content.get_rows(); i++)
            for (int j = 0; j < codeg.content.get_cols(); j++)
            {
                l = new Label(table, SWT.NONE);
                l.setText(Integer.toString(codeg.content.get_value(i, j)));
                l.setFont(f);
            }

        Button button = new Button(area, SWT.PUSH);
        button.setText("Edit");
        button.setLayoutData(new GridData(SWT.RIGHT, SWT.BOTTOM, true, false,
                1, 1));
        button.addListener(SWT.MouseUp, new Listener() {
            public void handleEvent(Event e)
            {
                TableCodegEditor editor = new TableCodegEditor();
                editor.run(area, codeg.content);
                codeg.changed();
            }
        });
    }

    public Codeg getCodeg() {
        return codeg;
    }

    public void setCodeg(Codeg codeg) {
        this.codeg = (MatrixCodeg) codeg;
    }

}
